home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / which100.zip / WHICH.C < prev    next >
C/C++ Source or Header  |  1993-03-12  |  6KB  |  217 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.     which.c                                        last revised:  12 Mar 93
  4.  
  5.     Program to find path of an executable command under either OS/2 or
  6.     (possibly) MS-DOS.  Not a lot of error-checking, but the array sizes
  7.     are reasonably generous.
  8.  
  9.     Copyright (c) 1993 by Greg Roelofs.  You may use this code for any pur-
  10.     pose whatsoever, as long as you don't sell it and don't claim to have
  11.     written it.  Not that you'd want to.
  12.  
  13.   ---------------------------------------------------------------------------*/
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20.  
  21. #ifndef TRUE
  22. #  define TRUE   1
  23. #  define FALSE  0
  24. #endif
  25.  
  26. #if defined(__OS2__) && !defined(OS2)
  27. #  define OS2
  28. #endif
  29.  
  30. #if defined(__IBMC__)
  31. #  define S_IFMT   0xF000   /* or (S_IFREG | S_IFDIR | S_IFCHR) */
  32. #endif
  33.  
  34. #ifndef S_ISDIR
  35. #  define S_ISDIR(m)   (((m) & S_IFMT) == S_IFDIR)
  36. #endif
  37.  
  38. #ifdef DEBUG
  39. #  define Trace(x)   fprintf x
  40. #else
  41. #  define Trace(x)
  42. #endif
  43.  
  44.  
  45. struct stat statbuf;
  46.  
  47. #ifdef OS2
  48.    static char *OS = "OS/2";
  49. #else
  50.    static char *OS = "MS-DOS";
  51. #endif
  52.  
  53. /* extensions must be in order of operating-system precedence! */
  54. static char *ext[] = {
  55.     ".com",
  56.     ".exe",
  57. #ifdef OS2
  58.     ".cmd",
  59. #endif
  60.     ".bat"
  61. };
  62.  
  63. /* OS/2 internal commands:  some of these are rarely used outside of
  64.  * command files, but all of them can be called from the command line.
  65.  * Technically I guess they're cmd.exe commands; 4OS2 presumably has
  66.  * other "internal OS/2 commands" which aren't included here.  (I may
  67.  * have screwed up in other ways, so if you find errors, let me know.
  68.  * I also don't know if some of the OS/2-only commands might be in later
  69.  * versions of MS-DOS...I suppose a better way to do this would be to
  70.  * use system() and check the errors, but that can wait for some other
  71.  * time.)
  72.  */
  73. static char *internal[] = {
  74. #ifdef OS2
  75.     "chcp",
  76.     "detach",
  77.     "dpath",
  78.     "endlocal",
  79.     "extproc",
  80.     "keys",
  81.     "move",
  82.     "setlocal",
  83.     "start",
  84. #endif
  85.     "call",
  86.     "cd",
  87.     "chdir",
  88.     "cls",
  89.     "copy",
  90.     "date",
  91.     "del",
  92.     "dir",
  93.     "echo",
  94.     "erase",
  95.     "exit",
  96.     "for",
  97.     "goto",
  98.     "if",
  99.     "md",
  100.     "mkdir",
  101.     "path",
  102.     "pause",
  103.     "prompt",
  104.     "rd",
  105.     "rem",
  106.     "ren",
  107.     "rename",
  108.     "rmdir",
  109.     "set",
  110.     "shift",
  111.     "time",
  112.     "type",
  113.     "ver",
  114.     "verify",
  115.     "vol"
  116. };
  117.  
  118.  
  119. int main(int argc, char *argv[])
  120. {
  121.     char *prognam, *p, *q, *path, *dir[1000], tempname[300];
  122.     int i, j, k, numdirs=0;
  123.     int numexts = sizeof(ext)/sizeof(char *);
  124.     int numinternal = sizeof(internal)/sizeof(char *);
  125.  
  126.  
  127.     prognam = argv[0];
  128.  
  129.     /* check for arguments; exit if none */
  130.     if (argc < 2) {
  131.         fprintf(stderr, "%s: too few arguments\n", prognam);
  132.         fprintf(stderr, "usage:  which cmd [cmd ...]\n");
  133.         exit(1);
  134.     }
  135.  
  136.     ++argv;
  137.     --argc;
  138.  
  139.     /* current directory is always implied, even if no path */
  140.     dir[numdirs++] = ".";
  141.  
  142.     /* terminate path elements and store pointers to each directory */
  143.     if ((path = getenv("PATH")) == (char *)NULL || *path == '\0') {
  144.         Trace((stderr, "\nPATH is empty\n\n"));
  145.     } else {
  146.         Trace((stderr, "\nPATH = %s\n\n", path));
  147.         if (*path != ';')
  148.             dir[numdirs++] = path;
  149.         p = path - 1;
  150.         while (*++p)
  151.             if (*p == ';') {
  152.                 *p = '\0';
  153.                 if ((p[1] != '\0') && (p[1] != ';'))
  154.                     dir[numdirs++] = p + 1;
  155.             } else
  156.                 *p = tolower(*p);  /* should probably make this an option... */
  157.     }
  158.  
  159.     /* for each command given as an argument, check all of the directories
  160.      * in the path:  first see if it's an internal command; if not, see if
  161.      * the OS will consider it a command as is (has a dot), and if so whether
  162.      * it exists; then try appending each extension (in order of precedence)
  163.      * and again check for existence in each path directory
  164.      */
  165.     for (j = 0;  j < argc;  ++j) {
  166.         int hasdot, found=FALSE;
  167.  
  168.         /* don't bother with internal commands if has a dot */
  169.         if (!(hasdot = (strchr(argv[j], (int)'.') != (char *)NULL))) {
  170.             for (i = 0;  (i < numinternal) && !found;  ++i) {
  171.                 Trace((stderr, "checking %s\n", internal[i]));
  172.                 if (stricmp(argv[j], internal[i]) == 0) {
  173.                     found = TRUE;
  174.                     printf("%s:  %s command-shell internal command\n",
  175.                       argv[j], OS);
  176.                     break;
  177.                 }
  178.             }
  179.         }
  180.         for (i = 0;  (i < numdirs) && !found;  ++i) {
  181.             p = tempname;
  182.             q = dir[i];
  183.             while (*p++ = *q++);  /* p now points to char *after* '\0' */
  184.             p[-1] = '\\';         /* replace null */
  185.             q = argv[j];
  186.             while (*p++ = *q++);  /* copy program name */
  187.             --p;                  /* point at null */
  188.             if (hasdot) {
  189.                 Trace((stderr, "checking %s\n", tempname));
  190.                 if (!stat(tempname, &statbuf) && !S_ISDIR(statbuf.st_mode)) {
  191.                     found = TRUE;
  192.                     printf("%s\n", tempname);
  193.                     break;
  194.                 }
  195.             }
  196.             for (k = 0;  (k < numexts) && !found;  ++k) {
  197.                 strcpy(p, ext[k]);
  198.                 Trace((stderr, "checking %s\n", tempname));
  199.                 if (!stat(tempname, &statbuf) && !S_ISDIR(statbuf.st_mode)) {
  200.                     found = TRUE;
  201.                     printf("%s\n", tempname);
  202.                     break;
  203.                 }
  204.             }
  205.         } /* end i-loop */
  206.  
  207.         if (!found) {
  208.             printf("no %s in", argv[j]);
  209.             for (i = 0;  i < numdirs;  ++i)
  210.                 printf(" %s", dir[i]);
  211.             printf("\n");
  212.         }
  213.     }
  214.  
  215.     return 0;
  216. }
  217.